using EasyAdmin.Admin.Entity.Entities;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace EasyAdmin.Admin.Application.Services.Impl
{
    public class SysMenuService : ISysMenuService
    {
        private readonly ISqlSugarClient _db;

        public SysMenuService(ISqlSugarClient db)
        {
            _db = db;
        }

        public async Task<List<MenuTreeDto>> GetMenuTreeAsync(long? userId = null)
        {
            var menus = await GetUserMenuListAsync(userId);
            return BuildMenuTree(menus);
        }

        public async Task<List<SysMenu>> GetMenuListAsync(string keyword = null)
        {
            var query = _db.Queryable<SysMenu>();
            
            if (!string.IsNullOrEmpty(keyword))
            {
                query = query.Where(m => m.MenuName.Contains(keyword));
            }

            return await query.OrderBy(m => m.OrderNum).ToListAsync();
        }

        public async Task<SysMenu> GetMenuByIdAsync(int menuId)
        {
            return await _db.Queryable<SysMenu>().FirstAsync(m => m.Id == menuId);
        }

        public async Task<(bool Success, string Message)> CreateMenuAsync(SysMenu menu)
        {
            menu.CreateTime = DateTime.Now;
            menu.Status = 1;

            var result = await _db.Insertable(menu).ExecuteCommandAsync() > 0;
            return (result, result ? "创建成功" : "创建失败");
        }

        public async Task<(bool Success, string Message)> UpdateMenuAsync(SysMenu menu)
        {
            var exists = await _db.Queryable<SysMenu>().AnyAsync(m => m.Id == menu.Id);
            if (!exists)
                return (false, "菜单不存在");

            menu.UpdateTime = DateTime.Now;
            var result = await _db.Updateable(menu)
                .IgnoreColumns(m => m.CreateTime)
                .ExecuteCommandAsync() > 0;

            return (result, result ? "更新成功" : "更新失败");
        }

        public async Task<(bool Success, string Message)> DeleteMenuAsync(int menuId)
        {
            // 检查是否有子菜单
            var hasChildren = await _db.Queryable<SysMenu>().AnyAsync(m => m.ParentId == menuId);
            if (hasChildren)
                return (false, "存在子菜单，不能删除");

            // 删除菜单及相关的角色-菜单关联记录
            await _db.Deleteable<SysRoleMenu>().Where(rm => rm.MenuId == menuId).ExecuteCommandAsync();
            var result = await _db.Deleteable<SysMenu>().Where(m => m.Id == menuId).ExecuteCommandAsync() > 0;

            return (result, result ? "删除成功" : "删除失败");
        }

        public async Task<List<int>> GetRoleMenuIdsAsync(int roleId)
        {
            var menuIds = await _db.Queryable<SysRoleMenu>()
                .Where(rm => rm.RoleId == roleId)
                .Select(rm => rm.MenuId)
                .ToListAsync();

            return menuIds;
        }

        public async Task<List<string>> GetUserPermissionsAsync(int userId)
        {
            // 获取用户角色关联的所有菜单权限标识
            var permissions = await _db.Queryable<SysUserRole>()
                .LeftJoin<SysRoleMenu>((ur, rm) => ur.RoleId == rm.RoleId)
                .LeftJoin<SysMenu>((ur, rm, m) => rm.MenuId == m.Id)
                .Where((ur, rm, m) => ur.UserId == userId && m.Status == 1)
                .Select((ur, rm, m) => m.Perms)
                .ToListAsync();

            return permissions.Where(p => !string.IsNullOrEmpty(p)).Distinct().ToList();
        }

        private async Task<List<SysMenu>> GetUserMenuListAsync(long? userId)
        {
            if (!userId.HasValue)
            {
                // 如果未指定用户ID，返回所有菜单
                return await _db.Queryable<SysMenu>()
                    .Where(m => m.Status == 1 && m.Visible == 1)
                    .OrderBy(m => m.OrderNum)
                    .ToListAsync();
            }

            // 获取用户角色关联的所有菜单
            var menus = await _db.Queryable<SysUserRole>()
                .LeftJoin<SysRoleMenu>((ur, rm) => ur.RoleId == rm.RoleId)
                .LeftJoin<SysMenu>((ur, rm, m) => rm.MenuId == m.Id)
                .Where((ur, rm, m) => ur.UserId == userId && m.Status == 1 && m.Visible == 1)
                .OrderBy((ur, rm, m) => m.OrderNum)
                .Select((ur, rm, m) => m)
                .ToListAsync();

            return menus;
        }

        private List<MenuTreeDto> BuildMenuTree(List<SysMenu> menus, long parentId = 0)
        {
            var tree = new List<MenuTreeDto>();

            var children = menus.Where(m => m.ParentId == parentId).OrderBy(m => m.OrderNum);
            foreach (var menu in children)
            {
                var node = new MenuTreeDto
                {
                    Id = menu.Id,
                    ParentId = menu.ParentId,
                    MenuName = menu.MenuName,
                    Path = menu.Path,
                    Component = menu.Component,
                    Perms = menu.Perms,
                    Icon = menu.Icon,
                    OrderNum = menu.OrderNum,
                    MenuType = menu.MenuType,
                    Visible = menu.Visible,
                    Children = BuildMenuTree(menus, menu.Id)
                };

                tree.Add(node);
            }

            return tree;
        }
    }
}